package com.zc.auth.security.core.authentication;

import com.alibaba.fastjson.JSON;
import com.zc.commons.user.dto.AuthorizedUser;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.util.StringUtils;

import java.util.Set;
import java.util.stream.Collectors;

/**
 * 凭据解析 封装为entity
 *
 * @author zcj
 * @version 1.0.0
 * @date 2022/1/13 10:57
 */
public interface AuthenticationTokenService<T extends AuthorizedUser> {

    enum TokenType {
        BEARER, BASIC
    }

    /**
     * 获取泛型类
     *
     * @return
     */
    Class<T> getSupportedClass();

    /**
     * 获取token解析的json
     *
     * @param str
     * @return
     */
    String getTokenJson(String token);

    /**
     * 根据凭据解析出{@link Authentication}
     *
     * @param str
     * @param clz
     * @return
     */
    default Authentication getAuthentication(String str) {
        // 校验token
        String token = this.checkToken(str, TokenType.BEARER);
        // 没有token直接返回匿名用户
        if (!StringUtils.hasLength(token)) {
            return new AnonymousAuthenticationToken();
        }
        String tokenJson = this.getTokenJson(token);
        // token解析为空抛出凭证失效异常
        if (!StringUtils.hasLength(tokenJson)) {
            throw new CredentialsExpiredException("凭证无效！");
        }
        // 获取登录用户实体
        T authUser = JSON.parseObject(tokenJson, this.getSupportedClass());
        if (authUser == null) {
            throw new CredentialsExpiredException("凭证无效！");
        }
        Set<SimpleGrantedAuthority> authorities = authUser.getRoleInfos().stream()
                .map(val -> new SimpleGrantedAuthority(val.getCode())).collect(Collectors.toSet());
        return new UsernamePasswordAuthenticationToken(authUser, str, authorities);
    }

    /**
     * 存储token
     *
     * @param key
     * @param json
     * @param expireTime
     */
    default void saveToken(String key, String json, long expireTime) {

    }

    /**
     * 校验token
     *
     * @param str
     * @return
     */
    default String checkToken(String str, TokenType tokenType) {
        if (!StringUtils.hasLength(str)) {
            return null;
        }
        String token;
        String tokenName = tokenType.name();
        String prefix = str.substring(0, tokenName.length());
        if (tokenName.equalsIgnoreCase(prefix)) {
            token = str.substring(tokenName.length());
        } else {
            throw new BadCredentialsException("无法解析token！");
        }
        return token.trim();
    }

    /**
     * 获取principal
     *
     * @param authentication
     * @return
     */
    default T getPrincipal(Authentication authentication) {
        return (T) authentication.getPrincipal();
    }


}
